/*
 * Copyright 2016-2019 yoara
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package yhao.infra.web.common.security.encrypt.helper;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import yhao.infra.apilist.ValidationForm;
import yhao.infra.common.util.MD5Util;
import yhao.infra.web.common.security.encrypt.EncryptCheckResult;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 加密组件基础父类
 *
 * @author yoara
 */
public abstract class AbstractEncryptHelper {
    protected Logger log = LoggerFactory.getLogger(this.getClass());

    protected static final String CHARACTER = "UTF-8";


    /**
     * 校验（加密）签名字符串
     * @param sign 客户端传递过来的已签名的字符串
     * @param map 参数Map
     * @param key 获取私钥的key值
     * @param onlyMD5 如果true，则只校验MD5签名
     */
    public EncryptCheckResult rsaCheck(String sign, Map<String,String> map, String key, boolean onlyMD5){
        if(map == null){
            return EncryptCheckResult.MATCHED;
        }
        String paramMD5 = getSign(map);
        return checkSign(sign, paramMD5,key,onlyMD5);
    }

    /**
     * 参数排序并用md5签名
     * @param map 要参与签名的数据对象
     * @return 签名
     * @throws IllegalAccessException
     */
    private String getSign(Map<String,String> map){
        ArrayList<String> list = getParamListByMap(map);
        return returnSign(list);
    }

    private String returnSign(ArrayList<String> list) {
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        //将最后一个分割字符去掉
        sb.deleteCharAt(sb.length()-1);
        String result = sb.toString();
        try {
            result = MD5Util.getMD5(result.getBytes(CHARACTER)).toUpperCase();
        } catch (UnsupportedEncodingException e) {}
        return result;
    }

    private ArrayList<String> getParamListByMap(Map<String, String> map) {
        ArrayList<String> list = new ArrayList<>();
        for(Map.Entry<String,String> entry:map.entrySet()){
            if(entry.getValue()!=""){
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        return list;
    }

    private JSONObject getParamMapByObject(Object o){
        JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(o));
        return json;
    }

    /**
     * 获取需要加密的参数串
     * @param paramAttrs 待校验字段
     * @param form 参数对象
     * @return
     */
    protected Map<String,String> makeCheckMap(String paramAttrs, ValidationForm form){
        if(StringUtils.isEmpty(paramAttrs)){
            return null;
        }
        String[] paramKeys = paramAttrs .split(",");
        JSONObject allParams = getParamMapByObject(form);
        Map<String,String> checkParam = new HashMap<>();
        for(String paramKey:paramKeys){
            String params = allParams.getString(paramKey);
            if(params!=null){
                checkParam.put(paramKey, params);
                continue;
            }
        }
        return checkParam;
    }

    protected abstract EncryptCheckResult checkSign(String sign, String paramMD5, String key, boolean onlyMD5);
}
